package com.zhb.cloud.config;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.zhb.cloud.cache.manager.ShrioRedisCacheManager;
import com.zhb.cloud.shiro.realm.MonitorRealm;

/**
 * @ClassName: ShiroConfig
 * @Description: Shiro整的配置文件
 * @author: zhb zhuhongbin@ehomepay.com.cn
 * @date: 2017年10月27日 上午10:30:22
 *
 */
@Configuration
@EnableCaching
public class ShiroConfig {
	@Autowired
	private ShrioRedisCacheManager shrioRedisCacheManager;

	public @Bean(name = "monitorRealm") MonitorRealm monitorRealm() {
		MonitorRealm monitorRealm = new MonitorRealm();
		monitorRealm.setCacheManager(shrioRedisCacheManager);
		return monitorRealm;
	}

	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@DependsOn("lifecycleBeanPostProcessor")
	public @Bean DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
		defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
		return defaultAdvisorAutoProxyCreator;
	}

	@Bean(name = "securityManager")
	public DefaultWebSecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(monitorRealm());
		// 用户授权/认证信息Cache, 采用EhCache 缓存
		// securityManager.setCacheManager(ehCacheManager);
		return securityManager;
	}

	public @Bean AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
		return authorizationAttributeSourceAdvisor;
	}

	/**
	 * 加载shiroFilter权限控制规则（从数据库读取然后配置）
	 * 
	 * @author zhb
	 */
	private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean) {
		// 下面这些规则配置最好配置到配置文件中
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		// authc：该过滤器下的页面必须验证后才能访问，它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
		filterChainDefinitionMap.put("/user/**", "anon");
		filterChainDefinitionMap.put("/question/**", "anon");
		filterChainDefinitionMap.put("/index*", "anon");
		filterChainDefinitionMap.put("/error*", "anon");
		filterChainDefinitionMap.put("/register*", "anon");
		filterChainDefinitionMap.put("/login*", "anon");
		filterChainDefinitionMap.put("/cache/**", "anon");
		filterChainDefinitionMap.put("/**", "authc");
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
	}

	/**
	 * ShiroFilter<br/>
	 * 注意这里参数中的 StudentService 和 IScoreDao 只是一个例子，因为我们在这里可以用这样的方式获取到相关访问数据库的对象，
	 * 然后读取数据库相关配置，配置到 shiroFilterFactoryBean 的访问规则中。实际项目中，请使用自己的Service来处理业务逻辑。
	 */
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		shiroFilterFactoryBean.setLoginUrl("/index");
		// 登录成功后要跳转的连接
		shiroFilterFactoryBean.setSuccessUrl("/main");
		shiroFilterFactoryBean.setUnauthorizedUrl("/shiro/error");
		loadShiroFilterChain(shiroFilterFactoryBean);
		return shiroFilterFactoryBean;
	}

	/**
	 * 异常处理
	 * 
	 * @return
	 */
	public @Bean SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
		SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
		Properties properties = new Properties();
		properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/error");
		exceptionResolver.setExceptionMappings(properties);
		return exceptionResolver;
	}

	public @Bean MethodInvokingFactoryBean methodInvokingFactoryBean() {
		MethodInvokingFactoryBean invokingFactoryBean = new MethodInvokingFactoryBean();
		invokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
		Object[] objects = new Object[] { securityManager() };
		invokingFactoryBean.setArguments(objects);
		return invokingFactoryBean;
	}
}
